<html>
    <head>
        <title>将原生事件绑定到组件</title>
    </head>
    <body>
        <script>
            //  将原生事件绑定到组件

                        /*
                            你可能有很多次想要在一个组件的根元素上"直接监听一个原生事件".
                            这时，你可以使用　v-on 的 .native 修饰符：

                               <base-input v-on:focus.native="onFocus"></base-input>


                            在有的时候这是很有用的，
                            不过在你尝试监听一个类似<input>的非常特定的元素时（想在组件外面监听组件内部的某个元素的原生事件），这并不是一个好主意。
                            比如，上述<base-input>组件可能做了如下重构，所以根元素实际上是一个<label>元素：

                                <label>
                                    {{label}}
                                    <input
                                         v-bind="$attrs"
                                         v-bind:value="value"
                                         v-on:input="$emit('input',$event.target.value)"
                                    >
                                </label>

                            这时，父级的 .native 监听器将静默失败。它不会产生任何报错，但是　onFocus 处理函数不会如你预期地被调用。
                        */

                        /*  
                            为了解决这个问题，Vue实例提供了一个 $listeners 属性，它是一个对象，里面包含了作用在这个组件上的"所有监听器"
                            （组件vue实例上会绑定一个 $listeners属性，包含了这个组件上的"所有监听器"）
                        */
                                // 例如：
                                    {
                                        focus:function(event){/*....*/},
                                        input:function(value){/*...*/}
                                    }

                        /*
                            有了这个$listeners 属性，你就可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的"某个子元素"。
                            （对于类似<input>的你希望它可以配合v-model工作的组件来说，为这个些监听器创建一个类似下述 inputListeners的计算属性通常是非常有用的：
                        */
                                    Vue.component('base-input',{
                                        inheritAttrs:false,
                                        props:['label','value'],
                                        computed:{
                                            inputListeners:function(){
                                                var vm=this;
                                                // 'Object.assign' 将所有的对象合并为一个新对象
                                                return Object.assign({},
                                                    // 从父级添加所有的监听器
                                                    this.$listeners,
                                                    // 然后我们添加自定义监听器 
                                                    // 或者重写一些监听器的行为
                                                    {
                                                        input: function(event){
                                                            vm.$emit('input',event.target.value);
                                                        }
                                                    }
                                                );
                                            }
                                        },
                                        template:`
                                            <label>
                                                {{label}}
                                                <input 
                                                     v-bind:"$attrs"
                                                     v-bind:value="value"
                                                     v-on="inputListeners"  // 添加监听器到input元素
                                                >
                                            </label>
                                        `
                                    });

                            /*
                                现在 <base-input>组件时一个"完全透明的包装器"了，也就是说，它可以完全像一个普通的<input>元素一样使用了：
                            */
        </script>
    </body>
</html>